package dstree

import "fmt"

const (
	Mean  = 0
	Stdev = 1
)

type Node_Split_Policy struct {
	Measure               int8    // 0为均值度量 1为标准差度量
	Split_From_idx        int16   //从哪个right point
	Split_To_idx          int16   //到哪个right point 度量mean或stdev
	Indicator_Split_Value Ts_type //记录中值
	//Series_Segment_Sketch Segment_Sketch
}

/*
measure = 0 :mean
measure = 1 :std
calculate split value = (indicator[measure*2]+indicator[measure*2+1])/2
0:max_mean
1:min_meam
2:max_std
3:min_std
*/
type Segment_Sketch struct {
	Indicators []Ts_type
}

func (ds *Dstree_Node) Node_split_policy_route_to_left(series []Ts_type) bool {
	//此节点用的分裂策略
	policy := ds.Split_Policy
	//是否分到到左节点
	route_to_left := false

	var series_segment_sketch Segment_Sketch
	series_segment_sketch.Indicators = make([]Ts_type, 2)
	if policy.Split_To_idx == 0 {
		fmt.Printf("%s,  policy split to idx==0 split policy=%v, point=%v\n", ds.Name, policy, ds.Node_Points)

	}
	Series_segment_sketch_do_sketch(&series_segment_sketch, series, policy.Split_From_idx, policy.Split_To_idx)

	if series_segment_sketch.Indicators[policy.Measure] < policy.Indicator_Split_Value {
		route_to_left = true
	}
	return route_to_left
}

func Series_segment_sketch_do_sketch(series_segment_sketch *Segment_Sketch, series []Ts_type, fromIdx, toIdx int16) {
	series_segment_sketch.Indicators[Mean] = Calc_Mean(series, fromIdx, toIdx)
	series_segment_sketch.Indicators[Stdev] = Calc_Stdev(series, fromIdx, toIdx)
}

// 每增加一个序列到node，更新sketch中的最大最小值
func Node_segment_sketch_update_sketch(node_segment_sketch *Segment_Sketch, series []Ts_type, fromIdx, toIdx int16) {

	var series_segment_sketch Segment_Sketch
	series_segment_sketch.Indicators = make([]Ts_type, 2)
	Series_segment_sketch_do_sketch(&series_segment_sketch, series, fromIdx, toIdx)

	node_segment_sketch.Indicators[0] = max(node_segment_sketch.Indicators[0], series_segment_sketch.Indicators[0])
	node_segment_sketch.Indicators[1] = min(node_segment_sketch.Indicators[1], series_segment_sketch.Indicators[0])
	node_segment_sketch.Indicators[2] = max(node_segment_sketch.Indicators[2], series_segment_sketch.Indicators[1])
	node_segment_sketch.Indicators[3] = min(node_segment_sketch.Indicators[3], series_segment_sketch.Indicators[1])
}

func (node *Dstree_Node) best_Split_Policy() (Node_Split_Policy, int16) {
	// fmt.Printf("%s needs to be split, Finding best policy\n", node.Name)
	var curr_node_split_policy Node_Split_Policy
	//维护目前最佳分裂策略的benefits
	var max_diff_value Ts_type
	max_diff_value = MintsType
	var hs_split_point int16
	hs_split_point = -1
	//test every possible split policy for each segment
	//for each segment
	num_node_points := len(node.Node_Points)
	for Sid := 0; Sid < num_node_points; Sid++ {
		curr_node_segment_sketch := node.Segment_Sketches[Sid]
		//This is the QoS of this segment. QoS is the estimation quality evaluated as =
		//QoS = segment_length * (max_mean_min_mean) * ((max_mean_min_mean) +
		//     (max_stdev * max_stdev))
		//The smaller the QoS, the more effective the bounds are for similarity
		//estimation
		//当前seg的range
		node_range_value := Range_calc(curr_node_segment_sketch, Get_Segment_Length(node.Node_Points, Sid))

		//for every split policy 0MEAN 1STDEV
		for measure := 0; measure < 2; measure++ {
			//curr_node_split_policy := node.node_segment_split_policies[j]
			//to hold the two child segments
			//分成两个孩子节点之后各自此seg的Sketch
			var child_node_segment_sketches [2]Segment_Sketch
			for k := 0; k < 2; k++ {
				child_node_segment_sketches[k].Indicators = make([]Ts_type, 4)
			}

			//(max+min)/2
			Split_Value := (curr_node_segment_sketch.Indicators[measure*2] +
				curr_node_segment_sketch.Indicators[measure*2+1]) / 2
			//更新孩子节点sketch
			//先复制
			for i := 0; i < 2; i++ {
				for j := 0; j < 4; j++ {
					child_node_segment_sketches[i].Indicators[j] = curr_node_segment_sketch.Indicators[j]
				}
			}
			//child1(origin min,splitvalue)
			//child2(splitvalue,origin max)
			child_node_segment_sketches[0].Indicators[measure*2+1] = Split_Value
			child_node_segment_sketches[1].Indicators[measure*2] = Split_Value
			//分成两个孩子节点之后各自此seg的benifit
			range_values1 := Range_calc(child_node_segment_sketches[0], Get_Segment_Length(node.Node_Points, Sid))
			range_values2 := Range_calc(child_node_segment_sketches[1], Get_Segment_Length(node.Node_Points, Sid))
			//diff_value represents the splitting benefit
			//B = QoS(N) - (QoS_leftNode + QoS_rightNode)/2
			//the higher the diff_value, the better is the splitting
			avg_children_range_value := (range_values1 + range_values2) / 2
			diff_value := node_range_value - avg_children_range_value

			//更新
			if diff_value > max_diff_value {
				max_diff_value = diff_value
				curr_node_split_policy.Split_From_idx = Get_Segment_Start(node.Node_Points, Sid)
				curr_node_split_policy.Split_To_idx = Get_Segment_End(node.Node_Points, Sid)
				curr_node_split_policy.Measure = int8(measure)
				curr_node_split_policy.Indicator_Split_Value = Split_Value
				//curr_node_split_policy.curr_node_segment_split_policy = curr_node_segment_split_policy;
			}
		}
	}

	//add trade-off for horizontal split
	max_diff_value = max_diff_value * 2
	//every possible Vertical split policy for each horizontal segment
	num_hs_node_points := len(node.Hs_split_points)
	for Sid := 0; Sid < num_hs_node_points; Sid++ {
		curr_node_segment_sketch := node.Hs_Segment_Sketches[Sid]
		//This is the QoS of this segment. QoS is the estimation quality evaluated as =
		//QoS = segment_length * (max_mean_min_mean) * ((max_mean_min_mean) +
		//     (max_stdev * max_stdev))
		//The smaller the QoS, the more effective the bounds are for similarity
		//estimation
		//当前seg的range
		node_range_value := Range_calc(curr_node_segment_sketch, Get_Segment_Length(node.Hs_split_points, Sid))

		//for every split policy 0MEAN 1STDEV
		for measure := 0; measure < 2; measure++ {
			//分成两个孩子节点之后各自此seg的Sketch
			var child_node_segment_sketches [2]Segment_Sketch
			for k := 0; k < 2; k++ {
				child_node_segment_sketches[k].Indicators = make([]Ts_type, 4)
			}
			//(max+min)/2
			Split_Value := (curr_node_segment_sketch.Indicators[measure*2] +
				curr_node_segment_sketch.Indicators[measure*2+1]) / 2
			//更新孩子节点sketch
			//先复制
			for i := 0; i < 2; i++ {
				for j := 0; j < 4; j++ {
					child_node_segment_sketches[i].Indicators[j] = curr_node_segment_sketch.Indicators[j]
				}
			}
			//child1(origin_min,splitvalue)
			//child2(splitvalue,origin_ mmax)
			child_node_segment_sketches[0].Indicators[measure*2+1] = Split_Value
			child_node_segment_sketches[1].Indicators[measure*2] = Split_Value
			//分成两个孩子节点之后各自此seg的benifit
			range_values1 := Range_calc(child_node_segment_sketches[0], Get_Segment_Length(node.Hs_split_points, Sid))
			range_values2 := Range_calc(child_node_segment_sketches[1], Get_Segment_Length(node.Hs_split_points, Sid))
			//diff_value represents the splitting benefit
			//B = QoS(N) - (QoS_leftNode + QoS_rightNode)/2
			//the higher the diff_value, the better is the splitting
			avg_children_range_value := (range_values1 + range_values2) / 2
			diff_value := node_range_value - avg_children_range_value

			//更新
			if diff_value > max_diff_value {
				max_diff_value = diff_value
				curr_node_split_policy.Split_From_idx = Get_Segment_Start(node.Hs_split_points, Sid)
				curr_node_split_policy.Split_To_idx = Get_Segment_End(node.Hs_split_points, Sid)
				curr_node_split_policy.Measure = int8(measure)
				curr_node_split_policy.Indicator_Split_Value = Split_Value
				//curr_node_split_policy.curr_node_segment_split_policy = curr_node_segment_split_policy;
				hs_split_point = Get_hs_split_point(node.Node_Points,
					curr_node_split_policy.Split_From_idx,
					curr_node_split_policy.Split_To_idx)
			}
		}
	}
	// if hs_split_point > 0 {
	// 	fmt.Printf("%s needs vertical split, best policy is %v\n", node.Name, curr_node_split_policy)
	// } else {
	// 	fmt.Printf("%s needs horizontal split, best policy is %v\n", node.Name, curr_node_split_policy)
	// }

	return curr_node_split_policy, hs_split_point
}
